/* UniApo
 * File:   DBSFile.h
 * Author: Jeffrey Geyssens
 *
 * Created on April 26, 2010, 6:09 PM
 * This is the header file for the DBSFile object, which is loaded when a
 * DBS file is created by the user or loaded from file.
 *
 * This object is created and used by the DBSEditor.
 * Manually modifying the physical file using a OS based text editor
 * may provoke errors when reading to the object, you have been warned!
 *
 * DBSFile is a subclass from UniApo file thus inherits the filename
 * and path conventions.
 *
 */

#ifndef _DBSFILE_H
#define	_DBSFILE_H

#include <iostream> //for input/output
#include <string> //for string operations
#include <fstream> //for files
#include "Section.h" //load section template
#include "DDLStatement.h" //load SQLStatement object for DDL statements.
#include "DMLStatement.h"
#include "UniApoFile.h" //load file superclass

using namespace std;

class DBSFile : public UniApoFile {
public:
    //constructor, destructor and copy constructor
    DBSFile();
    DBSFile(const DBSFile& orig);
    virtual ~DBSFile();

    //operations regarding DDL SQL statements
    void addStatement(string DDLStatement);
    void loadStatement(string DDLStatement);
    void modifyStatement(string DDLStatement, int entryNo);
    void removeStatement(int entryNo);

    //adding statements in bulk from any text file
    void bulk(string path);

    //Build file from object and Save to disk.
    void buildFile();

    //Print file contents to screen.
    void print();
    //Load file from given path in to this object.
    bool loadFile();

    //Give this option a name
    void name(string n);

    //For test DB creation
    void createtestDB();




private:
    Section<DDLStatement> DDLSection;
    Section<DMLStatement> DMLSection;
    void tempDDL();
    void revertDDL();
    void tempDML();

};

DBSFile::DBSFile() {
    this->DDLSection.setHeader(".DDL");
    this->DDLSection.setFooter(".END_DDL");
    this->DMLSection.setHeader(".DML");
    this->DMLSection.setFooter(".END_DML");
}

DBSFile::DBSFile(const DBSFile& orig) {
    filename = orig.filename;
    extension = orig.extension;
    path = orig.path;
    scriptpath = orig.path;
    DDLSection = orig.DDLSection;
    DMLSection = orig.DMLSection;
}

DBSFile::~DBSFile() {
}

void DBSFile::addStatement(string s) {
    if (s == "#") {
        cout << "procedure skipped" << endl;
    } else {
        if (s.find("CREATE TABLE") != s.npos) {
            DDLStatement DDLobject;
            if (DDLobject.addStatement(s) == false)
                cerr << "ERROR: SQL Statement contains errors" << endl;
            else this->DDLSection.add(DDLobject);
        } else {
            DMLStatement DMLobject;
            if (DMLobject.addStatement(s) == false)
                cerr << "ERROR: SQL Statement contains errors" << endl;
            else {
                
                this->tempDDL();
                this->DMLSection.add(DMLobject);
                this->revertDDL();
\

            }
        }

    }
}

void DBSFile::loadStatement(string s) {
    if (s == "#") {
        cout << "procedure skipped" << endl;
    } else {
        DDLStatement DDLobject;
        DDLobject.loadStatement(s);
        this->DDLSection.add(DDLobject);

    }
}

void DBSFile::modifyStatement(string s, int entryNo) {
    if ((s == "#") || (entryNo == 0)) {
        cout << "procedure skipped" << endl;
    } else {
        DDLStatement DDLobject;
        DDLobject.addStatement(s);
        if (DDLobject.getType() != DDL) {
            cerr << "You can only add DDL statements to a DBS File";
            cerr << endl;
        } else {
            this->DDLSection.modify(DDLobject, entryNo);

        }
    }
}

void DBSFile::removeStatement(int entryNo) {
    this->DDLSection.remove(entryNo);
}

void DBSFile::bulk(std::string path) {

    //This procedure allows the generation of a DBSFile using a text file
    //which contain DDL and DML statements.
    //This procedure simply scans a text file for the string CREATE_TABLE.
    //or INSERT_INTO.
    //It assumes the SQL statements are delimited by ; as is convention
    //for many popular DBMSs (mysql, postgresql, et al.)
    std::ifstream bulkFile(path.c_str());
    std::string line;

    if (bulkFile.is_open()) {

        string statement;
        int createtablepos, insertpos;
        int delimpos;

        while (!bulkFile.eof()) {
            getline(bulkFile, line);
            createtablepos = line.find("CREATE TABLE ");
            insertpos = line.find("INSERT INTO");
            if ((createtablepos != line.npos) &&
                    (createtablepos != line.npos)) {
                statement = line.substr(createtablepos, line.size());
                delimpos = line.find(";");
                if (delimpos != line.npos) {
                    statement = statement.substr(0, delimpos + 1);


                } else {
                    while (delimpos == line.npos) {
                        getline(bulkFile, line); //get new line
                        statement.append(line);
                        delimpos = line.find(";");

                    }
                }
                this->addStatement(statement);
            }

        }
        bulkFile.close();


    } else {
        cout << "file not found" << endl;
    }

}

void DBSFile::print() {
    this ->DDLSection.print();
    this ->DMLSection.print();
}

void DBSFile::buildFile() {
    ofstream newDBSFile;
    newDBSFile.open(path.c_str());
    newDBSFile << "filename: " << filename.c_str() << "\n";
    newDBSFile << "extension: " << extension.c_str() << "\n \n";
    newDBSFile.close();
    this ->DDLSection.buildFile(path);
    this ->DMLSection.buildFile(path);
}

bool DBSFile::loadFile() {
    ifstream DBSFile(path.c_str());
    string line;


    if (DBSFile.is_open()) {
        getline(DBSFile, line); //first line is mapname
        line = line.substr(10, line.size()); //ommit "filename:"
        filename = line.substr(0, line.size() - 4);
        extension = "DBS";

        while (line != ".DDL") {
            getline(DBSFile, line);
        }
        getline(DBSFile, line);
        while (line != ".END_DDL") {
            this->loadStatement(line);
            getline(DBSFile, line);
        }
        getline(DBSFile, line);
        while (line != ".DML") {
            getline(DBSFile, line);
        }
        getline(DBSFile, line);
        while (line != ".END_DML") {
            this->loadStatement(line);
            getline(DBSFile, line);
        }
        DBSFile.close();
        return true;
    } else return false;

}

//Give the DBSFile object

void DBSFile::name(string n) {
    filename = n;
    extension = "DBS";
    this->setPath();
}

//Create a local database using the DDL statements stored on file

void DBSFile::createtestDB() {
    this->tempDDL();
    this->tempDML();


}

void DBSFile::tempDDL() {
    vector<DDLStatement> v;
    v = DDLSection.getSectionData();
    vector<DDLStatement>::iterator it;

    for (it = v.begin(); it != v.end(); ++it) {
        (*it).test(); //Execute statement on uniapo_test database

    }
}

void DBSFile::revertDDL() {
    vector<DDLStatement> v;
    v = DDLSection.getSectionData();
    vector<DDLStatement>::iterator it;

    for (it = v.begin(); it != v.end(); ++it) {
        (*it).delTable(); //Execute statement on uniapo_test database

    }
}

void DBSFile::tempDML() {
    vector<DMLStatement> v;
    v = DMLSection.getSectionData();
    this->tempDDL();
    vector<DMLStatement>::iterator it;

    for (it = v.begin(); it != v.end(); ++it) {
        //(*it).execute(); //Execute statement on uniapo database
        (*it).test(); //Execute statement on uniapo_test database
    }
    this->revertDDL();
}
#endif	/* _DBSFILE_H */

